/**
 * @file UserEvent.c
 * @author lhc (liuhc_lhc@163.com)
 * @brief
 * @version 0.1
 * @date 2024-05-16
 *
 * @copyright Copyright (c) 2024
 *
 */

#include "UserEvent.h"
#include "FsmState.h"
#include "Fifo.h"
#include <stdio.h>
/********************每个函数分别实现以下内容即可**************************/

enum
{
    GSUC_FIFO_MAX = 32,
    EVENT_BUFF_MAX = 32,
};

static STR_STATE_INFO stStateTable[EVENT_BUFF_MAX]; // 任务缓存区fifo
static STR_STATE_MACHINE stStateMachine;            // 当前执行任务

static uint8_t sucEventFifo[GSUC_FIFO_MAX]; // 事件fifo 缓存区
static ring_buffer_t stFifoState;           // 事件fifo对象

/***************** 静态函数声明 *****************************/
static void StateStart(ENUM_EVENT_T event);  // 只写了一个示例函数
static void StateReset(ENUM_EVENT_T event);  // 空函数声明 //@todo 待完善
// static void StateAction(ENUM_EVENT_T event); // 空函数声明 //@todo 待完善

/**
 * @brief 对状态添加进行二次封装
 *
 * @param enCurState 当前状态
 * @param enEventId 事件ID
 * @param enNextState 当前状态+事件ID后 = 状态
 * @param pAction 执行动作
 */
static void staAdd(ENUM_STATE_T enCurState, ENUM_EVENT_T enEventId,
                   ENUM_STATE_T enNextState, VoidUint8FuncPtr pAction)
{
    FsmStateAdd(&stStateMachine, enCurState, enEventId, enNextState, pAction);
}
/**
 * @brief 初始化函数
 *
 */
void StaInit(void)
{
    ring_buffer_init(&stFifoState, (uint8_t *)&sucEventFifo, EVENT_BUFF_MAX); // fifo初始化
    FsmInit(&stStateMachine, stStateTable, EVENT_BUFF_MAX, kStateBegin);
    staAdd(kStateBegin, kEventBegin, kStateAction, (VoidUint8FuncPtr)StateStart);
    staAdd(kStateAction, kEventStop, kStateBegin, (VoidUint8FuncPtr)StateReset);
}

/**
 * @brief 写事件
 *
 * @param data
 * @return uint8_t
 */
void WriteEvent(ENUM_EVENT_T *data)
{
    ring_buffer_queue_arr(&stFifoState, (uint8_t *)data, 1);
}

/**
 * @brief 从环形缓冲区中读取事件数据
 *
 * 从指定的环形缓冲区中读取事件数据，并将其存储在提供的数据指针所指向的内存中。
 *
 * @param fifo 指向环形缓冲区的指针
 * @param data 指向用于存储读取到的事件数据的指针
 *
 * @return 如果成功读取数据，则返回1；如果环形缓冲区为空，则返回0
 */
static uint8_t ReadEvent(void* fifo, ENUM_EVENT_T* data)
{
    if (fifo == NULL || data == NULL) {
        return 0;
    }
    if (ring_buffer_is_empty((ring_buffer_t*)fifo)) {
        return 0;
    }
    return ring_buffer_dequeue((ring_buffer_t*)fifo, (uint8_t *)data);
}

/**
 * @brief 主状态处理函数
 *
 * 此函数负责从事件队列中读取事件，并调用状态机来处理这些事件。
 *
 * @return 无返回值
 */
void StateMain(void)
{
#if 1
    ENUM_EVENT_T ucEvent      = 0;
    uint8_t      ucStateIndex = 0;

    while (ReadEvent(&stFifoState, &ucEvent) != 0 && ucStateIndex++ < GSUC_FIFO_MAX) {
        FsmMachineRun(&stStateMachine, (ENUM_EVENT_T)ucEvent);
    }
#else
    FsmProcessEvents(&stStateMachine, &stFifoState, ReadEvent, 0);
#endif
}

/************************函数实现 begin***********************************/

/**
 * @brief 事件处理函数
 *
 * @param event 传入事件
 */
static void StateStart(ENUM_EVENT_T event)
{
    switch (event)
    {
    case kEventBegin: // begin
        printf("kEventBegin event\r\n");
        break;
    default:
        // note lhc 默认什么都不做,如果需要做,请谨慎思考后添加 确定是否可以添加,这里可能会有隐患哦
        printf("default event\r\n");
        break;
    }
}

static void StateReset(ENUM_EVENT_T event)
{
    switch (event)
    {
    case kEventStop: // stop
        printf("kEventStop event\r\n");
        break;
    default:
        // note lhc 默认什么都不做,如果需要做,请谨慎思考后添加 确定是否可以添加,这里可能会有隐患哦
        //  这里并不应该执行,如果执行了就是用法错误
        printf("default event\r\n");
        break;
    }
}

/************************函数实现 end***********************************/

/**
 * @brief 测试demo1 其实这个demo不是很合理
 * @todo 实际执行任务时 直接循环调用 StateMain()即可
 * 写入事件在外部其他模块写入
 * 因为 StateMain() 是周期调用 所以事件写入后 能及时处理
 * 所以这一段其实没什么用可以删除
 */
void StateDemo(void)
{
    uint8_t ucEvent = kEventBegin;
    printf("write event kEventBegin :");
    WriteEvent((ENUM_EVENT_T *)&ucEvent); // 写入开始事件

    printf("\r\nwrite event kEventBegin :");
    WriteEvent((ENUM_EVENT_T *)&ucEvent); // 重复写入开始事件

    printf("\r\nwrite event kEventStop :");
    ucEvent = kEventStop;
    WriteEvent((ENUM_EVENT_T *)&ucEvent); // 写入停止事件

    printf("\r\nwrite event NULL----------------------: ");
    WriteEvent((ENUM_EVENT_T *)&ucEvent); // 重复写入停止事件 无动作

    printf("\r\nwrite event kEventBegin:");
    ucEvent = kEventBegin;
    WriteEvent((ENUM_EVENT_T *)&ucEvent); // 切换状态后写入开始事件

    printf("\r\nwrite event kEventBegin:");

    WriteEvent((ENUM_EVENT_T *)&ucEvent); // 写入多个事件 未能及时处理
    printf("\r\nwrite event kEventStop:");
    ucEvent = kEventBegin;
    WriteEvent((ENUM_EVENT_T *)&ucEvent); // 写入多个事件 未能及时处理
    printf("\r\n------------------------\r\n");
}
